#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
商品handle模块
'''

from lib.myweb import WebApplication
from lib.myweb import Dispatcher
from lib.myweb import Render
from lib.validate import Filter
from lib.validate import Check

from common import auth
from common.myconfig import CONF
from common.myvalidate import ValidatorCommon
from common.mydata import ModelItem
from common.mydata import ModelUser


class FilterItem(Filter):
    '商品模块专用过滤器'
    @staticmethod
    def parse_photo(photo_bin):
        '解析图片并检查是否符合条件'
        from PIL import Image
        import StringIO

        try:
            str_io = StringIO.StringIO(photo_bin)
            img = Image.open(str_io)
        except:
            return None

        photo = {}
        photo['photo_bin'] = photo_bin
        photo['format_type'] = img.format.lower()
        photo['width'] = img.size[0]
        photo['height'] = img.size[1]
        photo['file_size'] = len(photo_bin)

        if not ValidatorItem.check_photo(photo):
            return None
        else:
            return photo

    @staticmethod
    def parse_tags(target_str):
        '解析标签并判断是否合法'
        import re

        encoding = CONF['encoding']

        target_str = target_str.decode(encoding)
        target_str, num = re.subn(u'，', ',', target_str)
        target_str = target_str.encode(encoding)
        tags = target_str.split(',')
        if len(tags) > 5:
            return None
        for tag in tags:
            if not ValidatorItem.check_tag(tag):
                return None
        # 去掉重复的标签
        tags = list(set(tags))
        return tags


class ValidatorItem(ValidatorCommon):
    '商品模块专用校验器'
    @staticmethod
    @Check.is_len_range(6, 30)
    @Check.is_re_match(u'^[a-zA-Z0-9\u4E00-\u9FA5（）\(\)\-\/ ]*$')
    def check_itemname(target_str):
        '检查商品名称'
        return True

    @staticmethod
    @Check.is_len_range(4, 12)
    @Check.is_re_match(u'^[0-9a-zA-Z\u4E00-\u9FA5]*$')
    def check_tag(target_str):
        '检查单个标签'
        return True

    @staticmethod
    @Check.is_len_range(1, 8)
    @Check.is_digit(True)
    def check_price(target_str):
        '检查价格'
        return True

    @staticmethod
    @Check.is_len_range(20, 1000)
    def check_detail(target_str):
        '检查商品详情'
        return True

    @staticmethod
    def check_photo(photo):
        '检查图片'
        format_list = ['jpg', 'jpeg', 'png']
        # 图片尺寸限制，单位为像素
        size_min = (200, 100)
        size_max = (1000, 500)
        # 文件大小限制，单位为字节
        file_size_limit = 1024 * 100

        img_size = (photo['width'], photo['height'])
        if photo['format_type'] not in format_list:
            return False
        if img_size < size_min:
            return False
        if img_size > size_max:
            return False
        if photo['file_size'] > file_size_limit:
            return False
        return True

    @staticmethod
    @Check.is_empty
    @Check.is_len_range(1, 6)
    @Check.is_alnum(False)
    def check_type(target_str):
        '检查搜索类型'
        return True


class RenderItem(Render):
    '商品模块专用渲染器'
    CONTENT_TYPE = Render.CONTENT_TYPE
    CONTENT_TYPE['image'] = 'image/'

    @property
    def content_type(self):
        '返回渲染响应的http报文类型，用于设置头响应'
        content_type = super(RenderItem, self).content_type
        if self.mode == 'image':
            content_type += self.args['image_format']
        return content_type

    def render_image(self):
        '以图像形式输出'
        return self.view


class HandleItem(WebApplication):
    '商品handle'
    _HANDLE_NAME = 'item'  # handle名称，用于模板前缀
    _PATH_PREFIX = '/item'  # 一级路径名称，用于解析path

    @auth.session(auth.SESSION_LEVEL['user'])
    def action_new(self):
        '新建商品表单'
        pass

    @auth.method('post')
    @auth.session(auth.SESSION_LEVEL['user'])
    @auth.token
    def action_newproc(self):
        '新建商品处理页面'
        import MySQLdb

        # 表单信息检查
        form = self._request.form

        # 检查普通信息
        check_list = [
                'itemname',
                'price',
                'detail',
                ]
        item_info, error_type = ValidatorItem.check_from_dict(form, check_list)
        if error_type:
            return self.error_type(error_type)

        # 检查图片信息
        photo = form.get('photo', None)
        photo_info = FilterItem.parse_photo(photo)
        if not photo_info:
            return self.error_type('photo')

        # 检查标签信息
        tags = form.get('tags', None)
        tags = FilterItem.parse_tags(tags)
        if not tags:
            return self.error_type('tags')

        # 添加物品信息到数据库
        photo_info['photo_bin'] = MySQLdb.Binary(photo_info['photo_bin'])
        item_info['owner_id'] = self._session['user_info']['id']
        mod_itm = ModelItem()
        item_info = mod_itm.create(item_info, photo_info, tags)

        if not item_info:
            return self.error_type(error_type)

        self._render.view['item_info'] = item_info

    @auth.session(auth.SESSION_LEVEL['visitor'])
    def action_show(self):
        '商品详情展示页'
        self._render.view['item_info'] = {}

        # 检查表单
        query = self._request.query
        item_info, error_type = ValidatorItem.check_from_dict(query, ['id', ])
        if error_type:
            return self.error_type(error_type)

        mod_itm = ModelItem()
        item_info = mod_itm.select_by_id_join(item_info['id'])

        if not item_info:
            return self.error_type('not_exist')

        self._render.view['item_info'] = item_info

    @auth.session(auth.SESSION_LEVEL['visitor'])
    def action_photo(self):
        '根据商品ID返回其图片'
        from common.mydata import ModelPhoto

        image_notfound = CONF['image_notfound']
        self._render.mode = 'image'
        self._render.args['image_format'] = CONF['image_notfound_format']

        # 检查表单
        query = self._request.query
        item_info, error_type = ValidatorItem.check_from_dict(query, ['id', ])
        if error_type:
            self._render.view = open(image_notfound, 'rb').read()
            return

        mod_pht = ModelPhoto()
        photo_info = mod_pht.select_by_item_id(item_info['id'])
        if photo_info:
            self._render.view = photo_info['photo_bin']
            self._render.args['image_format'] = photo_info['format_type']
        else:
            self._render.view = open(image_notfound, 'rb').read()

    @auth.session(auth.SESSION_LEVEL['user'])
    def action_del(self):
        '删除商品确认页'
        query = self._request.query
        item_info, error_type = ValidatorItem.check_from_dict(query, ['id', ])
        if error_type:
            return self.error_type(error_type)

        # 判断商品是否存在，是否本人，是否已卖
        mod_itm = ModelItem()
        item_info = mod_itm.select_by_id_join(item_info['id'])
        if not item_info:
            return self.error_type('not_exist')
        if item_info['owner_id'] != self._session['user_info']['id']:
            return self.error_type('not_yours')
        if item_info['buyer_id']:
            return self.error_type('already_sold')

        self._render.view['item_id'] = item_info['id']

    @auth.method('post')
    @auth.session(auth.SESSION_LEVEL['user'])
    @auth.token
    def action_delproc(self):
        '删除商品'
        form = self._request.form
        item_info, error_type = ValidatorItem.check_from_dict(form, ['id', ])
        if error_type:
            return self.error_type(error_type)

        mod_itm = ModelItem()
        res = mod_itm.remove(item_info['id'], self._session['user_info']['id'])
        if not res:
            return self.error_type('fail')

    @auth.session(auth.SESSION_LEVEL['user'])
    def action_buy(self):
        '购买商品确认页'
        query = self._request.query
        item_info, error_type = ValidatorItem.check_from_dict(query, ['id', ])
        if error_type:
            return self.error_type(error_type)

        mod_itm = ModelItem()
        item_info = mod_itm.select_by_id_join(item_info['id'])
        if not item_info:
            return self.error_type('not_exist')
        if item_info['owner_id'] == self._session['user_info']['id']:
            return self.error_type('is_yours')
        if item_info['buyer_id']:
            return self.error_type('already_sold')
        account = self._session['user_info']['account']
        if int(item_info['price']) > int(account):
            return self.error_type('not_enough_money')

        self._render.view['item_id'] = item_info['id']

    @auth.method('post')
    @auth.session(auth.SESSION_LEVEL['user'])
    @auth.token
    def action_buyproc(self):
        '购买商品处理页'
        #query = self._request.query
        query = self.arg_dict
        item_info, error_type = ValidatorItem.check_from_dict(query, ['id', ])
        if error_type:
            return self.error_type(error_type)

        mod_itm = ModelItem()
        res = mod_itm.buy(item_info['id'], self._session['user_info']['id'])
        if not res:
            return self.error_type('fail')

        self._render.view['item_info'] = item_info

    @auth.session(auth.SESSION_LEVEL['visitor'])
    def action_available(self):
        '获取可买的商品，支持翻页，用json格式返回'
        self._render.mode = 'json'
        self._render.view = {}

        page_size = CONF['page_size']
        num_max = CONF['num_max']
        num_start = 0

        query = self._request.query
        check_list = ['offset', 'num']
        page_info, error_type = ValidatorItem.check_from_dict(
                query, check_list)
        if error_type:
            self._render.view['result'] = 'invalidate'
            return
        offset = int(page_info['offset']) if page_info['offset'] else num_start
        num = int(page_info['num']) if page_info['num'] else page_size
        if num > num_max:
            num = num_max

        mod_itm = ModelItem()
        limits = (offset, num)
        records = mod_itm.select_by_available(limits)
        if not records:
            self._render.view['result'] = 'empty'
            return

        for record in records:
            record['special'] = 'buy'

        self._render.view['result'] = 'ok'
        self._render.view['records'] = records

    @auth.session(auth.SESSION_LEVEL['visitor'])
    def action_list(self):
        '查找特定ID拥有的商品，可翻页，返回json格式'
        import cgi

        self._render.mode = 'json'

        page_size = CONF['page_size']
        num_max = CONF['num_max']
        num_start = 0

        query = self._request.query
        checklist = ['id', 'offset', 'num', 'type']
        page_info, error_type = ValidatorItem.check_from_dict(query, checklist)
        if error_type:
            self._render.view = {'result': 'invalidate'}
            return
        offset = int(page_info['offset']) if page_info['offset'] else num_start
        num = int(page_info['num']) if page_info['num'] else page_size
        if num > num_max:
            num = num_max
        query_type = page_info['type']
        if query_type != 'own' and query_type != 'buy':
            self._render.view = {'result': 'invalidate'}
            return

        # 获取拥有的商品信息
        mod_itm = ModelItem()
        limits = (offset, num)
        user_id = page_info['id']
        if query_type == 'own':
            records = mod_itm.select_by_owner(user_id, limits)
        else:
            records = mod_itm.select_by_buyer(user_id, limits)
        if not records:
            self._render.view = {'result': 'empty'}
            return

        # 如果是用户查看自己的商品，则再寻找买家信息
        if self._session:
            is_self = (int(user_id) == self._session['user_info']['id'])
        else:
            is_self = False
        if (query_type == 'own') and is_self:
            mod_usr = ModelUser()
            for item_own in records:
                buyer_id = item_own['buyer_id']
                if buyer_id:
                    item_own['buyer_info'] = mod_usr.select_by_id(buyer_id)
                    # 进行html转义
                    item_own['buyer_info']['address'] = \
                            cgi.escape(item_own['buyer_info']['address'])

        for record in records:
            if query_type == 'own':
                if not record['buyer_id']:
                    record['special'] = 'del'
                elif is_self:
                    record['special'] = 'connect'
                else:
                    record['special'] = ''

        self._render.view = {'result': 'ok'}
        self._render.view['records'] = records


dispatcher = Dispatcher()
dispatcher.add_route('buy/proc/{id}', 'buyproc')
application = HandleItem(render=RenderItem(), dispatcher=dispatcher)
